/*
 * Daniel R Padilla
 *
 * Copyright (c) 2007, Daniel R Padilla
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.databasefacade.table;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;

import org.databasefacade.DatabaseHelper;
import org.databasefacade.table.column.Column;
import org.databasefacade.table.column.ColumnMetaData;
import org.databasefacade.table.column.datatype.DataType;
import org.databasefacade.table.column.datatype.DataTypeFactory;
import org.databasefacade.table.column.datatype.DateDataType;
import org.databasefacade.table.row.Row;


public class Table
{
	private String ENTRY_TIMESTAMP = "ENTRY_TIMESTAMP";
	private String MODIFY_TIMESTAMP = "MODIFY_TIMESTAMP";
	private Row columnDefinitions;
	private String tableName;
	private String tableTitle;
	private String tableAlias;
	private boolean isConfigTable = false;   
	private ConstraintKey primaryKey;
	private ConstraintKeyList foreignKeys = new ConstraintKeyList();
	private String outputFileName;
	
	/**
	 * Database Helper should be available everywhere 
	 */
	private DatabaseHelper databaseHelper;

	/** Delete table dependency. This lets the program know if a record in the table 
	 * can be deleted. If it is empty then it cannot be deleted. A master with no
	 * details only has itself as a dependence.
	 */
	private ArrayList deleteTableDependancies = new ArrayList();
    
	public Table(DatabaseHelper helper, String table)
	{
		init(helper, table, null, null, null);
	}

	public Table(DatabaseHelper helper, String table, ConstraintKey primaryKey)
	{
		init(helper, table, primaryKey, null, null);
	}
    
	public Table(DatabaseHelper helper, String table, ConstraintKey primaryKey, String entryField, String modifyField)
	{
		init(helper, table, primaryKey, entryField, modifyField);
	}
    
	private void init(DatabaseHelper helper, String table, ConstraintKey primaryKey, String entryField, String modifyField)
	{
    	
		this.databaseHelper = helper;
		
		// Initialize the absolute needed information
		setTableName(table.toUpperCase());
		setTableTitle(titleCase(getTableName()));
		setTableAlias(getTableName());
		if ( primaryKey != null ) {
			this.primaryKey = primaryKey;
		}
		columnDefinitions = new Row(this);
        
		// Setup the primary key after the minimum table parameters have been initialized
		if ( primaryKey == null ) {
			DataTypeFactory factory = new DataTypeFactory(helper.getTranslator());
			DataType dt = factory.getInstance(DataType.AUTO_INCREMENT_TYPE);
			Column col = new Column(this, table + "_KEY", dt);
			primaryKey = new ConstraintKey(col);
			this.primaryKey = primaryKey;
		}
    	
		if ( entryField != null ) {
			MODIFY_TIMESTAMP = entryField.toUpperCase();
		}
		if ( modifyField != null ) {
			MODIFY_TIMESTAMP = modifyField.toUpperCase();
		}
               
		// Initialize the rest of the table

		for ( int i = 0; i < primaryKey.getKeyColumns().size(); i++ ) {
			Column pc = primaryKey.getKeyColumns().getColumn(i);
			columnDefinitions.addColumn(pc);
		}
		Column col = new Column(this, getEntryTimestampColumnName(), new DateDataType(helper.getTranslator()));
		columnDefinitions.addColumn(col);
		col = new Column(this, getModifyTimestampColumnName(), new DateDataType(helper.getTranslator()));
		columnDefinitions.addColumn(col);
		Column cr = columnDefinitions.getColumn(getEntryTimestampColumnName());

		ColumnMetaData cmd = cr.getDatabaseMetaData();
		cmd.setIsUniqueField(false);
		cmd.setIsRequired(false);
        
		cr = columnDefinitions.getColumn(getModifyTimestampColumnName());
		cmd = cr.getDatabaseMetaData();
		cmd.setIsUniqueField(false);
		cmd.setIsRequired(false);
	}
	
	public DatabaseHelper getDBHelper() {
		return databaseHelper;
	}
    
	public void setTableName(String t)
	{
		tableName = t;
	}
    
	public String getTableName()
	{
		return tableName;
	}
	
	public void setOutputFileName(String t)
	{
		outputFileName = t;
	}
    
	public String getOutputFileName()
	{
		return outputFileName;
	}
    
	public void setTableTitle(String t)
	{
		tableTitle = t;
	}
    
	public String getTableTitle()
	{
		return tableTitle;
	}
    
	public void setTableAlias(String alias)
	{
		tableAlias = alias;
		if ( columnDefinitions != null ) {
			for ( int i = 0; i < columnDefinitions.numberOfColumns(); i++ ) {
				Column col = columnDefinitions.getColumn(i);
				col.setTableAlias(tableAlias);
			}
		}
	}
    
	public String getTableAlias()
	{
		return tableAlias;
	}
    
	public void setIsConfigTable(boolean isConfig)
	{
		isConfigTable = isConfig;
	}
    
	public boolean isConfigTable()
	{
		return isConfigTable;
	}
        
	public String getEntryTimestampColumnName()
	{
		return ENTRY_TIMESTAMP;
	}
    
	public String getModifyTimestampColumnName()
	{
		return MODIFY_TIMESTAMP;
	}
    
	public boolean tableExists(String tableName)
	{
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;

		try {
			conn = getDBHelper().getConnection();
			conn.setAutoCommit(true);
			// TBD-Use-Select
			String sql = "SELECT * FROM " + tableName + " LIMIT 1";
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			rs.close();
			ps.close();
			conn.close();
			return true;
		} catch ( Exception e ) {
			try {
				if ( rs != null ) {
					rs.close();
				}
				if ( ps != null ) {
					ps.close();
				}
				if ( ps != null ) {
					conn.close();
				}	    			
			} catch ( Exception ee ) {}
			return false;
		}
	}
              
	public Iterator getColumnNames()
	{
		return columnDefinitions.getColumnNames();
	}

	public Column getColumn(String col)
	{
		Column column = columnDefinitions.getColumn(col);
		return column;
	}
    
	public void addColumn(Column col)
	{
		columnDefinitions.addColumn(col);
	}
        
	private String titleCase(String tableName)
	{
		boolean toUpper = true;
		String formattedText = "";

		for ( int i = 0; i < tableName.length(); i++ ) {
			String ch = "";

			if ( i < tableName.length() - 1 ) {
				ch = tableName.substring(i, i + 1);
			} else {
				ch = tableName.substring(i);
			}
			if ( ch.equals("_") ) {
				toUpper = true;
				formattedText += ' ';
			} else {
				if ( toUpper ) {
					formattedText += ch.toUpperCase();
					toUpper = false;
				} else {
					formattedText += ch;
				}
			}
    		
		}
		return formattedText;
	} 
    
	public void setIsDeletable(boolean canBeDeleted)
	{
		if ( canBeDeleted ) {
			deleteTableDependancies.add(getTableName());
		} else {
			deleteTableDependancies = new ArrayList();
		}
	}
    
	public void addDeleteDependentTable(String tableName)
	{
		deleteTableDependancies.add(tableName);
	}
    
	public void removeDeleteDependentTable(String tableName)
	{
		deleteTableDependancies.remove(tableName);
	}
    
	public boolean isDeletable()
	{
		return (deleteTableDependancies.size() > 0);
	}
    
	public void setPrimaryKey(ConstraintKey key)
	{
		primaryKey = key;
	}
    
	public ConstraintKey getPrimaryKey()
	{
		return primaryKey;
	}
    
	public void addForeignKey(ConstraintKey key)
	{
		foreignKeys.addKey(key);
	}
    
	public void addForeignKeys(ConstraintKeyList keys)
	{
		for ( int i = 0; i < keys.size(); i++ ) {
			foreignKeys.addKey(keys.getKey(i));
		}
	}
    
	public ConstraintKeyList getForeignKeys()
	{
		return foreignKeys;
	}
    
	public Table getCopy()
	{
		Table newTable = new Table(databaseHelper, new String(this.getTableName()), primaryKey.getCopy(), 
			new String(this.getEntryTimestampColumnName()), 
			new String(this.getModifyTimestampColumnName()));
		newTable.setIsConfigTable(this.isConfigTable());
		Iterator columns = this.getColumnNames();
		while ( columns.hasNext() ) {
			String colName = columns.next().toString();
			Column col = this.getColumn(colName);
			newTable.addColumn(col.getCopy());
		}
		newTable.setPrimaryKey(this.getPrimaryKey().getCopy());
		newTable.addForeignKeys(this.getForeignKeys().getCopy());
		newTable.setTableAlias(this.getTableAlias());
		newTable.setOutputFileName(this.getOutputFileName());
		return newTable;
	}
    
	public String toString()
	{
		return "Table: " + getTableName() + columnDefinitions.toString();
	}
	
}
